package org.osite.xml;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.osite.util.Preconditions;
import org.w3c.dom.Attr;

public class DefaultAttributeHandler<T> implements AttributeHandler<T> {

    private final Method setter;
    private final AttributeConverter<?> convertor;
    private final Class<?> paramType;

    public DefaultAttributeHandler(Method setter, ConvertorProvider provider)
            throws ParseSetupException {
        this.setter = Preconditions.checkNotNull(setter);
        Class<?> types[] = setter.getParameterTypes();
        if (types.length != 1) {
            throw new ParseSetupException(
                    "invalid setter(multiple arguments): " + setter);
        }
        paramType = types[0];
        this.convertor = provider.getAttributeConverter(types[0]);
        if (convertor == null) {
            throw new ParseSetupException("no converter for " + types[0]);
        }
    }

    public DefaultAttributeHandler(Method setter,
            AttributeConverter<?> convertor) throws ParseSetupException {
        this.setter = Preconditions.checkNotNull(setter);
        this.convertor = Preconditions.checkNotNull(convertor);
        Class<?> types[] = setter.getParameterTypes();
        if (types.length != 1) {
            throw new ParseSetupException(
                    "invalid setter(multiple arguments): " + setter);
        }
        paramType = types[0];
    }

    @Override
    public void process(T component, Attr attr, ParseContext context)
            throws XmlParseException {
        if (convertor == null) {
            throw new XmlParseException("no convertors for type: "
                    + paramType + " in method: " + setter);
        }
        try {
            setter.invoke(component, new Object[]{convertor.convert(paramType,
                    attr.getValue(), context)});
        } catch (IllegalArgumentException e) {
            throw new XmlParseException("fail to invoke setters of attribute: "
                    + attr, e, attr);
        } catch (IllegalAccessException e) {
            throw new XmlParseException("fail to invoke setters of attribute: "
                    + attr, e, attr);
        } catch (InvocationTargetException e) {
            throw new XmlParseException("fail to invoke setters of attribute: "
                    + attr, e, attr);
        } catch (XmlParseException e) {
            e.setWhere(attr);
            throw e;
        }
    }
    
}
